<?php

/**
 * Class User
 *
 * @property string nickname
 *
 * @author Hua Yang <htmlcook@gmail.com>
 * @package common.models
 * @since 1.0
 */
class User extends BaseUser
{
	const ANONYMOUS_NAME = '匿名用户';

	/**
	 * @var integer 超级管理员ID
	 */
	const ROOT_ID = 1;

	/**
	 * @var array 角色名称列表
	 */
	private $_roleNames;

	/**
	 * @var array 角色列表
	 */
	private $_roles;

	/**
	 * @param string $className
	 * @return User
	 */
	public static function model($className = __CLASS__)
	{
		return parent::model($className);
	}

	public function tableName()
	{
		return '{{user}}';
	}

	public function rules()
	{
		return array_merge(parent::rules(), array(
			array('roleNames', 'safe'),
		));
	}

	public function attributeLabels()
	{
		return array_merge(parent::attributeLabels(), array(
			'roleNames' => '角色',
		));
	}

	/**
	 * @return CActiveDataProvider
	 */
	public function search()
	{
		$criteria = new CDbCriteria;

		$criteria->compare('id', $this->id, true);
		$criteria->compare('username', $this->username, true);
		$criteria->compare('nickname', $this->nickname, true);
		$criteria->compare('email', $this->email, true);
		$criteria->compare('status', $this->status);
		$criteria->compare('update_time', $this->update_time);

		if ($this->create_time) {
			$condition = YUtil::generateTimeCondition($this->create_time, 't.create_time');
			if ($condition) {
				$criteria->addCondition($condition);
			}
		}

		if (isset($this->login_time)) {
			if (is_numeric($this->login_time)) {
				$criteria->compare('login_time', $this->login_time);
			} elseif ($this->login_time) {
				$condition = YUtil::generateTimeCondition($this->login_time, 't.login_time');
				if ($condition) {
					$criteria->addCondition($condition);
				}
			}
		}

		if (isset($this->_roleNames) && $this->_roleNames) {
			$criteria->join = 'INNER JOIN ' . Yii::app()->getAuthManager()->assignmentTable . ' AS t2 ON t.id = t2.userid';
			$criteria->addInCondition('t2.itemname', (array)$this->_roleNames);
		}

		return new CActiveDataProvider($this, array(
			'criteria' => $criteria,
			'sort' => array(
				'defaultOrder' => 't.id DESC'
			)
		));
	}

	/**
	 * 获取角色列表
	 */
	public function getRoleList()
	{
		$list = CHtml::listData($this->getRoles(), 'name', 'description');
		return $list;
	}

	/**
	 * 获取角色列表
	 *
	 * @return array
	 */
	public function getRoles()
	{
		$authManager = Yii::app()->getAuthManager();
		if (!isset($this->_roles)) {
			if ($this->isNewRecord) {
				$this->_roles = array();
			} else {
				$this->_roles = $authManager->getRoles($this->id);
			}
		}

		return $this->_roles;
	}

	/**
	 * 设置角色列表
	 *
	 * @param array $names 角色名称或者角色列表
	 */
	public function setRoles($names)
	{
		$this->_roles = array();
		$authManager = Yii::app()->getAuthManager();
		foreach ((array)$names as $name) {
			if ($name instanceof CAuthItem) {
				$this->_roles[] = $name;
			} else {
				if ($role = $authManager->getAuthItem($name)) {
					$this->_roles[] = $role;
				}
			}
		}
	}

	/**
	 * 是否拥有角色$name
	 *
	 * @param string $name
	 * @return bool
	 */
	public function hasRole($name)
	{
		$roles = $this->getRoles();
		foreach ($roles as $role) {
			if ($role->getName() == $name) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 添加一个角色
	 *
	 * @param string $name 角色名
	 */
	public function addRole($name)
	{
		$roleNames = $this->getRoleNames();
		if (!in_array($name, $roleNames)) {
			$roleNames[] = $name;
			$this->setRoleNames($roleNames);
			$this->saveRoles();
		}
	}

	/**
	 * 获取角色名称列表
	 *
	 * @return array
	 */
	public function getRoleNames()
	{
		if (!isset($this->_roleNames)) {
			$this->_roleNames = array();
			foreach ($this->getRoles() as $role) {
				$this->_roleNames[] = $role->name;
			}
		}
		return $this->_roleNames;
	}

	/**
	 * 设置角色名称列表
	 *
	 * @param array $names
	 */
	public function setRoleNames($names)
	{
		$this->_roleNames = array();
		foreach ((array)$names as $name) {
			if ($name = trim($name)) {
				$this->_roleNames[] = $name;
			}
		}
		$this->setRoles($names);
	}

	/**
	 * 保存角色列表
	 */
	protected function saveRoles()
	{
		if (!isset($this->_roles) || !is_array($this->_roles)) {
			return;
		}

		$addRoles = array();
		$delRoles = array();
		if ($this->isNewRecord) {
			$addRoles = $this->_roles;
		} else {
			$oldRoles = Yii::app()->getAuthManager()->getRoles($this->id);

			foreach ($this->_roles as $role) {
				foreach ($oldRoles as $oldRole) {
					if ($role->getName() == $oldRole->getName()) {
						continue 2;
					}
				}
				$addRoles[] = $role;
			}

			foreach ($oldRoles as $oldRole) {
				foreach ($this->_roles as $role) {
					if ($oldRole->getName() == $role->getName()) {
						continue 2;
					}
				}
				$delRoles[] = $oldRole;
			}
		}

		foreach ($addRoles as $role) {
			$role->assign($this->id);
		}

		foreach ($delRoles as $role) {
			$role->revoke($this->id);
		}

		Yii::app()->getCache()->set("user_{$this->id}_roles", $this->_roles);
	}

	/**
	 * 删除一个角色
	 *
	 * @param string $name 角色名
	 */
	public function removeRole($name)
	{
		if (in_array($name, Role::$defaultRoles)) {
			return;
		}

		$roleNames = $this->getRoleNames();
		if (($index = array_search($name, $roleNames)) !== false) {
			unset($roleNames[$index]);
			$this->setRoleNames($roleNames);
			$this->saveRoles();
		}
	}

	/**
	 * 取消账户
	 *
	 * @param string $method
	 * @return bool
	 */
	public function cancel($method)
	{
		if (!in_array($method, array('block', 'block_unpublish', 'reassign', 'delete'))) {
			return false;
		}

		switch ($method) {
			case 'block':
				if ($this->status != self::STATUS_BLOCK) {
					$this->status = self::STATUS_BLOCK;
					$this->update('status');
				}
				return true;
			case 'block_unpublish':
				if ($this->status != self::STATUS_BLOCK) {
					$this->status = self::STATUS_BLOCK;
					$this->update('status');
				}
				foreach (Channel::model()->getTree() as $channel) {
					if ($channel->type != Channel::TYPE_LIST) {
						continue;
					}
					$staticModel = CActiveRecord::model($channel->getBundleClass());
					if (!$staticModel instanceof Node) {
						continue;
					}
					$staticModel->bulkUpdate(array('status' => Node::STATUS_DRAFT), 'user_id=:user_id', array(':user_id' => $this->id));
				}
				return true;
			case 'reassign':
				if ($this->delete()) {
					foreach (Channel::model()->getTree() as $channel) {
						if ($channel->type != Channel::TYPE_LIST) {
							continue;
						}
						$staticModel = CActiveRecord::model($channel->getBundleClass());
						if (!$staticModel instanceof Node) {
							continue;
						}
						$staticModel->bulkUpdate(array('user_id' => 0), 'user_id=:user_id', array(':user_id' => $this->id));
					}
					File::model()->bulkUpdate(array('user_id' => 0), 'user_id=:user_id', array(':user_id' => $this->id));
					return true;
				} else {
					return false;
				}
			case 'delete':
				if ($this->delete()) {
					foreach (Channel::model()->getTree() as $channel) {
						if ($channel->type != Channel::TYPE_LIST) {
							continue;
						}
						$staticModel = CActiveRecord::model($channel->getBundleClass());
						if (!$staticModel instanceof Node) {
							continue;
						}
						$staticModel->bulkDelete('user_id=:user_id', array(':user_id' => $this->id));
					}
					File::model()->bulkDelete('user_id=:user_id', array(':user_id' => $this->id));
					return true;
				} else {
					return false;
				}
			default:
				return false;
		}
	}

	/**
	 * 删除之前
	 *
	 * @see CActiveRecord::beforeDelete()
	 */
	protected function beforeDelete()
	{
		if (parent::beforeDelete()) {
			if ($this->id == self::ROOT_ID) {
				return false;
			}
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 保存之前
	 *
	 * @see CActiveRecord::beforeSave()
	 */

	/**
	 * 保存之后
	 *
	 * @see CActiveRecord::afterSave()
	 */
	protected function afterSave()
	{
		parent::afterSave();
		$this->saveRoles();
	}

	/**
	 * 删除之后
	 *
	 * @see CActiveRecord::afterDelete()
	 */
	protected function afterDelete()
	{
		parent::afterDelete();
		$this->deleteRoles();
		Yii::app()->getWatchDog()->write('user_delete',
			'用户：%id %username %email 删除',
			array('%id'=>$this->id, '%name' => $this->username, '%email' =>$this->email));
	}

	/**
	 * 删除用户所有角色
	 */
	protected function deleteRoles()
	{
		foreach ($this->getRoles() as $role) {
			$role->revoke($this->id);
		}
	}
}

